package linguo.level;

import java.awt.Graphics;


import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;

import javax.swing.JOptionPane;

import linguo.Data;
import linguo.Game;
import linguo.level.mapObjects.Casillero;
import linguo.level.mapObjects.CasilleroTransitable;
import linguo.level.mapObjects.Coleccionable;
import linguo.level.mapObjects.MapObject;
import linguo.level.mapObjects.coleccionable.Baliza;
import linguo.level.mapObjects.coleccionable.Cono;
import linguo.level.mapObjects.destruible.Caja;
import linguo.level.mapObjects.destruible.ParedDestruible;
import linguo.level.mapObjects.destruible.Planta;
import linguo.level.mapObjects.misc.CasilleroFinal;
import linguo.level.mapObjects.misc.CasilleroVoid;
import linguo.level.mapObjects.nodestruible.Concreto;
import linguo.level.mapObjects.notransitable.Agua;
import linguo.level.mapObjects.notransitable.Fuego;
import linguo.level.mapObjects.premio.PremioMunicion;
import linguo.level.mapObjects.premio.PremioNafta;
import linguo.level.mapObjects.premio.PremioPuntos;
import linguo.level.mapObjects.transitable.Arena;
import linguo.level.mapObjects.transitable.Asfalto;


/**
 *Tablero del juego
 *@author Corpaz German
 *@author Frank Andres
 *
 */

public class Board {

	protected Game game;
	protected Casillero[][] tablero;
	protected File archivo;

	protected ArrayList<Casillero> casilleros;
	protected ArrayList<MapObject> objetos;
	protected ArrayList<MapObject> objetosRemover;

	private final int SPACE = Data.SPRITE_SIZE;
	private final int FILAS = (600 / Data.SPRITE_SIZE);
	private final int COLUMNAS = (800 / Data.SPRITE_SIZE);

	public Board(Game game, String nivel, File nivelDeArchivo) {
		this.game = game;
		tablero = new Casillero[game.getWIDTH()][game.getHEIGHT()];
		archivo = nivelDeArchivo;
		casilleros = new ArrayList<Casillero>();
		objetos = new ArrayList<MapObject>();
		objetosRemover = new ArrayList<MapObject>();

		initWorld(nivel);
	}

	/**
	 * Recibe un string con el nombre del nivel, si el nombre es "De archivo" procede a cargar del atributo archivo
	 * @param nivel Nombre del nivel seleccionado en la comboBox
	 */
	private void initWorld(String nivel) {
		try {
			BufferedReader br = null;
			String seleccion= nivel.substring(nivel.length()-14, nivel.length()-4);
		
			
			if (!(seleccion.equals("De archivo"))) br = new BufferedReader(new InputStreamReader(getClass().getResourceAsStream(nivel)));
			else {
				FileReader fr = null;

				fr = new FileReader(archivo);
				br = new BufferedReader(fr);

			}

			String linea = "";
			int filas = 0;
			int columnas = 0;
				filas = Integer.parseInt(br.readLine());
				columnas = Integer.parseInt(br.readLine());


				// ___________ Inicializacion del nivel
				int x = ((COLUMNAS - columnas) / 2) * SPACE;
				int y = ((FILAS - filas) / 2) * SPACE;

				Casillero c;
				CasilleroTransitable ct;
				MapObject m;
				int corrimientos;

				for (int i = 0; i < filas; i++) {
					try {
						linea = br.readLine();

					} catch (IOException e) {
					}
					corrimientos = 0;

					for (int j = 0; j < columnas; j++) {

						char item = linea.charAt(j * 2 + corrimientos);

						switch (item) {
							case '_' : {
								c = new Asfalto(this, x, y);
								casilleros.add(c);
								dibujar(x, y, c);
								x += SPACE;
								break;
							}

							case '#' : {
								c = new Arena(this, x, y);
								casilleros.add(c);
								dibujar(x, y, c);
								x += SPACE;
								break;
							}

							case '&' : {
								c = new Fuego(this, x, y);
								casilleros.add(c);
								dibujar(x, y, c);
								x += SPACE;
								break;
							}

							case '@' : {
								c = new Agua(this, x, y);
								casilleros.add(c);
								dibujar(x, y, c);
								x += SPACE;
								break;
							}

							case 'F' : {

								CasilleroFinal cf = new CasilleroFinal(this, x, y);
								casilleros.add(cf);
								dibujar(x, y, cf);
								x += SPACE;
								break;
							}

							case 'S' : {
								if (linea.charAt(j * 2 + corrimientos + 1) == '_') ct = new Asfalto(this, x, y);
								else ct = new Arena(this, x, y);
								casilleros.add(ct);
								corrimientos++;
								dibujar(x, y, ct);

								game.getRobot().setX(x);
								game.getRobot().setY(y);
								x += SPACE;
								break;
							}

							case '+' : {
								if (linea.charAt(j * 2 + corrimientos + 1) == '_') ct = new Asfalto(this, x, y);
								else ct = new Arena(this, x, y);
								casilleros.add(ct);
								corrimientos++;

								PremioNafta pn = new PremioNafta(this, x, y, ct);
								objetos.add(pn);
								ct.setObjeto(pn);

								dibujar(x, y, ct);

								x += SPACE;
								break;
							}

							case '*' : {
								if (linea.charAt(j * 2 + corrimientos + 1) == '_') ct = new Asfalto(this, x, y);
								else ct = new Arena(this, x, y);
								casilleros.add(ct);
								corrimientos++;

								PremioMunicion pn = new PremioMunicion(this, x, y, ct);
								objetos.add(pn);
								ct.setObjeto(pn);

								dibujar(x, y, ct);

								x += SPACE;
								break;
							}

							case '$' : {
								int cantidad = 1;
								while ((linea.charAt(j * 2 + corrimientos + 1) != '#') && (linea.charAt(j * 2 + corrimientos + 1) != '_')) {
									corrimientos++;
									cantidad++;
								}
								if (linea.charAt(j * 2 + corrimientos + 1) == '_') ct = new Asfalto(this, x, y);
								else ct = new Arena(this, x, y);
								casilleros.add(ct);
								corrimientos++;

								PremioPuntos pn = new PremioPuntos(this, x, y, ct);

								switch (cantidad) {
									case 1 :
										pn.setPuntos(5);
										break;
									case 2 :
										pn.setPuntos(10);
										break;
									case 3 :
										pn.setPuntos(50);
										break;
									case 4 :
										pn.setPuntos(100);
										break;
								}
								objetos.add(pn);
								ct.setObjeto(pn);

								dibujar(x, y, ct);

								x += SPACE;
								break;
							}

							case 'X' : {
								if (linea.charAt(j * 2 + corrimientos + 1) == '_') ct = new Asfalto(this, x, y);
								else ct = new Arena(this, x, y);
								casilleros.add(ct);
								corrimientos++;

								m = new Concreto(this, x, y, ct);
								objetos.add(m);
								ct.setObjeto(m);

								dibujar(x, y, ct);

								x += SPACE;
								break;
							}

							case '!' : {

								if (linea.charAt(j * 2 + corrimientos + 1) == '_') ct = new Asfalto(this, x, y);
								else ct = new Arena(this, x, y);

								corrimientos++;
								casilleros.add(ct);

								Coleccionable cl = new Cono(this, x, y, ct);
								objetos.add(cl);
								ct.setObjeto(cl);

								dibujar(x, y, ct);

								x += SPACE;
								break;
							}

							case '?' : {

								if (linea.charAt(j * 2 + corrimientos + 1) == '_') ct = new Asfalto(this, x, y);
								else ct = new Arena(this, x, y);
								Coleccionable cl = new Baliza(this, x, y, ct);
								corrimientos++;
								casilleros.add(ct);
								objetos.add(cl);
								ct.setObjeto(cl);

								dibujar(x, y, ct);

								x += SPACE;
								break;
							}

							case '{' : {

								int ind = j * 2 + corrimientos;
								int pospremio = ind + 1;
								int cantidad = 0;

								while (linea.charAt(ind + 1) != '}') {
									corrimientos++;
									ind++;
									cantidad++;
								}
								corrimientos = corrimientos + 2;
								if (linea.charAt(ind + 2) == '_') ct = new Asfalto(this, x, y);
								else ct = new Arena(this, x, y);

								Planta planta = new Planta(this, x, y, ct);
								ct.setObjeto(planta);
								casilleros.add(ct);
								objetos.add(planta);
								dibujar(x, y, ct);

								if (ind > 0) {
									char premio;

									premio = linea.charAt(pospremio);

									switch (premio) {
										case '+' : {
											PremioNafta pn = new PremioNafta(this, x, y, ct);
											planta.asignarPremio(pn);
											break;
										}
										case '*' : {
											PremioMunicion pm = new PremioMunicion(this, x, y, ct);
											planta.asignarPremio(pm);
											break;
										}
										case '$' : {
											PremioPuntos pp = new PremioPuntos(this, x, y, ct);

											switch (cantidad) {
												case 1 :
													pp.setPuntos(5);
													break;
												case 2 :
													pp.setPuntos(10);
													break;
												case 3 :
													pp.setPuntos(50);
													break;
												case 4 :
													pp.setPuntos(100);
													break;
											}
											planta.asignarPremio(pp);
											break;
										}
									}
								}
								x += SPACE;
								break;
							}

							case '[' : {

								int ind = j * 2 + corrimientos;
								int pospremio = ind + 1;
								int cantidad = 0;

								while (linea.charAt(ind + 1) != ']') {
									corrimientos++;
									ind++;
									cantidad++;
								}
								corrimientos = corrimientos + 2;
								if (linea.charAt(ind + 2) == '_') ct = new Asfalto(this, x, y);
								else ct = new Arena(this, x, y);

								Caja caja = new Caja(this, x, y, ct);
								ct.setObjeto(caja);
								casilleros.add(ct);
								objetos.add(caja);
								dibujar(x, y, ct);

								if (ind > 0) {
									char premio;

									premio = linea.charAt(pospremio);

									switch (premio) {
										case '+' : {
											PremioNafta pn = new PremioNafta(this, x, y, ct);
											caja.asignarPremio(pn);
											break;
										}
										case '*' : {
											PremioMunicion pm = new PremioMunicion(this, x, y, ct);
											caja.asignarPremio(pm);
											break;
										}
										case '$' : {
											PremioPuntos pp = new PremioPuntos(this, x, y, ct);

											switch (cantidad) {
												case 1 :
													pp.setPuntos(10);
													break;
												case 2 :
													pp.setPuntos(20);
													break;
												case 3 :
													pp.setPuntos(50);
													break;
												case 4 :
													pp.setPuntos(100);
													break;
											}
											caja.asignarPremio(pp);
											break;
										}
									}
								}
								x += SPACE;
								break;
							}

							case '|' : {

								int ind = j * 2 + corrimientos;
								int pospremio = ind + 1;
								int cantidad = 0;

								while (linea.charAt(ind + 1) != '|') {
									corrimientos++;
									ind++;
									cantidad++;
								}
								corrimientos = corrimientos + 2;
								if (linea.charAt(ind + 2) == '_') ct = new Asfalto(this, x, y);
								else ct = new Arena(this, x, y);

								ParedDestruible paredDestruible = new ParedDestruible(this, x, y, ct);
								ct.setObjeto(paredDestruible);
								casilleros.add(ct);
								objetos.add(paredDestruible);
								dibujar(x, y, ct);

								if (ind > 0) {
									char premio;

									premio = linea.charAt(pospremio);

									switch (premio) {
										case '+' : {
											PremioNafta pn = new PremioNafta(this, x, y, ct);
											paredDestruible.asignarPremio(pn);
											break;
										}
										case '*' : {
											PremioMunicion pm = new PremioMunicion(this, x, y, ct);
											paredDestruible.asignarPremio(pm);
											break;
										}
										case '$' : {
											PremioPuntos pp = new PremioPuntos(this, x, y, ct);

											switch (cantidad) {
												case 1 :
													pp.setPuntos(10);
													break;
												case 2 :
													pp.setPuntos(20);
													break;
												case 3 :
													pp.setPuntos(50);
													break;
												case 4 :
													pp.setPuntos(100);
													break;
											}
											paredDestruible.asignarPremio(pp);
											break;
										}
									}
								}
								x += SPACE;
								break;
							}

							default:
								x += SPACE;
								break;
						}
					}
					y += SPACE;
					x = ((COLUMNAS - columnas) / 2) * SPACE;
				}

				for (int i = 0; i < game.getWIDTH(); i++)
					for (int j = 0; j < game.getHEIGHT(); j++)
						if (tablero[i][j] == null) tablero[i][j] = new CasilleroVoid(this, i, j);
			
		} catch (Exception e) {
			JOptionPane.showMessageDialog(null, "Error al cargar archivo.", "Error", JOptionPane.ERROR_MESSAGE);
			game.terminarJuego();
		}
	}

	
	/**
	 * Dibuja un casillero en el canvas
	 * @param x posicion x
	 * @param y posicion y
	 * @param o Tipo de casillero a dibujar
	 */
	private void dibujar(int x, int y, Casillero o) {
		for (int i = 0; i < SPACE; i++)
			for (int j = 0; j < SPACE; j++)
				tablero[x + i][y + j] = o;

	}

	/**
	 * Remueve los objetos del tablero
	 */
	public void update() {
		while (objetosRemover.size() > 0)
			objetos.remove(objetosRemover.remove(0));
	}

	
	public void render(Graphics g) {
		for (int i = 0; i < casilleros.size(); i++)
			casilleros.get(i).render(g);

		for (int i = 0; i < objetos.size(); i++)
			objetos.get(i).render(g);
	}

	/**
	 * Obtiene el casillero situado en la posicion pasada como parametro
	 * 
	 * @param x la posicion en x del casillero
	 * @param y la posicion en y del casillero
	 * @return el casillero situado en la posicion pasada como parametro
	 */
	public Casillero getCasillero(int x, int y) {
		return tablero[x][y];
	}

	/**
	 * Agrega un objeto a la lista de objetos del tablero
	 * 
	 * @param obj objeto a agregar al tablero
	 */
	public void agregarObjeto(MapObject obj) {
		objetos.add(obj);
	}

	/**
	 * Agrega un objeto a la lista de objetos que seran removidos del tablero
	 * 
	 * @param obj objeto a remover del tablero
	 */
	public void removerObjeto(MapObject obj) {
		objetosRemover.add(obj);
	}

	/**
	 * Le avisa al juego que el robot llego al casillero final y gano el juego.
	 */
	public void ganarJuego() {
		game.ganarJuego();
	}

	/**
	 * Recibe un archivo y lo guarda
	 * @param Archivo para cargar el nivel en caso de que la seleccion sea "De archivo"
	 */
	public void setArchivo(File a) {
		archivo = a;
	}
}
